/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-06
 * V4.0
 */
package com.jphenix.servlet.multipart.instancea;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import com.jphenix.share.lang.WebParameterMap;
import com.jphenix.share.util.BaseUtil;
import com.jphenix.share.util.SFilesUtil;
import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.servlet.api.ICookie;
import com.jphenix.standard.servlet.api.IHttpSession;
import com.jphenix.standard.servlet.api.IRequest;
import com.jphenix.standard.servlet.api.IRequestDispatcher;
import com.jphenix.standard.servlet.api.ServletInputStream;


/**
 * 上传文件处理类
 * com.jphenix.service.multipart.instancea.MultipartServletRequest
 * 
 * 2019-08-31 修改了连续上传2个文件，第二个文件上传内容大小错误的问题
 * 2020-01-13 修改了上传无扩展名文件时，文件名保存错误的问题
 * 2020-01-15 在上传文件的同时传参时，对参数主键和名字也做URL解码
 * 2022-09-04 隔离了ServletApi，兼容新老Tomcat
 * 
 * @author 刘虻
 * 2007-3-12下午04:06:14
 */
@ClassInfo({"2022-09-04 21:58","上传文件处理类"})
public class MultipartServletRequest {

	/**
	 * 上传后保存的扩展名（在文件名后附加的扩展名）
	 * 防止上传不良文件
	 */
	public final static String SAVED_EXT_NAME = ".saved";
	
	protected int    bufferSize      = 256; //读取缓存
	protected String tagParaName     = "name="; //获取参数名标识
	protected String tagParaFileName = "filename=";//获取上传文件名
	protected String basePath        = null;//保存根路径
	protected String tempPath        = null; //临时相对文件夹
	
	protected Map<String,List<String>> fileNameMap     = null; //文件名对照容器 key tagName  value保存后的文件名
	protected Map<String,List<String>> fileRealNameMap = null; //文件名对照容器 key tagName value保存前的文件名
	protected Map<String,String[]>     parameterMap    = null; //参数容器
	protected IRequest                 request         = null; //页面请求
	protected ServletInputStream       webInputStream  = null; //页面读入流
	
	/**
	 * 迭代器类
	 * @author 刘虻
	 * 2007-3-13上午10:02:37
	 */
	protected class EnumerationImpl implements Enumeration<String> {

		protected String[] objs = null; //元素数组
		protected int index = 0; //指针
		
		/**
		 * 构造函数
		 * 2007-3-13上午10:03:42
		 */
		public EnumerationImpl(String[] objs) {
			super();
			this.objs = objs;
		}
		
		/**
		 * 覆盖方法
		 * @author 刘虻
		 * 2007-3-13上午10:04:19
		 */
		@Override
        public boolean hasMoreElements() {
            return objs != null && objs.length > index;
        }

		/**
		 * 覆盖方法
		 * @author 刘虻
		 * 2007-3-13上午10:04:49
		 */
		@Override
        public String nextElement() {
			//构造返回值
			String reObj = objs[index];
			index++;
			return reObj;
		}
		
	}
	
	
	/**
	 * 构造函数
	 * 2007-3-12下午04:06:14
	 */
	public MultipartServletRequest(
			IRequest httpServletRequest
			,String basePath,String tempPath) {
		super();
		this.request  = httpServletRequest;
		this.basePath = basePath;
		this.tempPath = tempPath;
		if(this.tempPath==null) {
			this.tempPath = "";
		}
		doFixRequest(); //执行解析页面请求
	}



	/**
	 * 获取文件名对照容器 key tagName  value保存后的文件名
	 * @author 刘虻
	 * 2007-3-12下午05:47:58
	 * @return 文件名对照容器 key tagName  value保存后的文件名
	 */
	public Map<String,List<String>> getFileNameMap() {
		if (fileNameMap==null) {
			fileNameMap = new WebParameterMap<String,List<String>>();
		}
		return fileNameMap;
	}


	/**
	 * 设置文件名对照容器 key tagName  value保存后的文件名
	 * @author 刘虻
	 * 2007-3-12下午05:48:07
	 * @param fileNameMap 文件名对照容器 key tagName  value保存后的文件名
	 */
	public void setFileNameMap(WebParameterMap<String,List<String>> fileNameMap) {
		this.fileNameMap = fileNameMap;
	}


    /**
     * 获取参数容器
     * @author 刘虻
     * 2007-3-12下午05:48:22
     * @return 参数容器
     */
    public Map<String,String[]> getParameterMap() {
        if (parameterMap==null) {
            parameterMap = new WebParameterMap<String,String[]>();
            parameterMap.putAll(request.getParameterMap());
        }
        return parameterMap;
    }
    

	/**
	 * 设置参数容器
	 * @author 刘虻
	 * 2007-3-12下午05:48:27
	 * @param parameterMap 参数容器
	 */
	public void setParameterMap(WebParameterMap<String,String[]> parameterMap) {
		this.parameterMap = parameterMap;
	}
	

	/**
	 * 获取文件名对照容器 key tagName value文件保存前的文件名
	 * @author 刘虻
	 * 2007-3-12下午09:53:35
	 * @return 文件名对照容器 key tagName value文件保存前的文件名
	 */
	public Map<String,List<String>> getFileRealNameMap() {
		if (fileRealNameMap==null) {
			fileRealNameMap = new WebParameterMap<String,List<String>>();
		}
		return fileRealNameMap;
	}

	
	/**
	 * 设置文件名对照容器 key tagName value文件保存前的文件名
	 * @author 刘虻
	 * 2007-3-12下午09:54:09
	 * @param fileRealNameMap 文件名对照容器 key tagName value文件保存前的文件名
	 */
	public void setFileRealNameMap(WebParameterMap<String,List<String>> fileRealNameMap) {
		this.fileRealNameMap = fileRealNameMap;
	}



	/**
	 * 执行解析页面请求
	 * @author 刘虻
	 * 2007-3-12下午05:50:40
	 */
	protected void doFixRequest() {
		
		//构造缓存
		byte[] bufferBytes = new byte[bufferSize]; 
		
		/*
		 *  为了截获文件结束标识 13 10 设置了读取一行然后更新上一行
		 *  
		 *  设置了两个缓存，先将头两次读出的信息分别保存在两个缓存中
		 *  第三次读入信息后，再将头一个缓存信息写入文件
		 *  
		 *  因为有可能出现以下情况
		 *  
		 *  第一次读取信息缓存占满，第二次只读取到了 13 10
		 *  
		 *  第一次读取信息缓存占满，但结尾是13，第二次读取只收到了10
		 *  
		 *  通常情况：
		 *  
		 *  	第一次读取缓存未满结束。
		 *  	非头一次读取缓存未满结束（非满，但不会只接收到 13 10 或者  只有10）。
		 *  
		 *  头两次
		 */
		int bufferType = 1; //缓存指针
		byte[] lastReadBytes1 = new byte[bufferSize]; //缓存指针1
		byte[] lastReadBytes2 = new byte[bufferSize]; //缓存指针2
		int lastReadSize1 = 0; //上一次读取字节数
		int lastReadSize2 = 0; //上一次读取字节数
		
		
		
		int allSize = request.getContentLength(); //内容总长度
		int correntSize = 0; //当前读入长度
		int readSize = 0; //实际读取字节数
		
		int fileNo = 0; //文件索引
		String pointStr = null; //分割符
		String lineStr = ""; //行信息
		boolean isFirst = true; //是否首次读取
		boolean readParaName = false; //是否准备读取参数信息
		boolean readFileValue = false; //是否读取文件内容
		boolean readParaValue = false; //是否读取参数内容
		String paraNameStr = null; //参数名
		StringBuffer paraValue = new StringBuffer(); //参数值
		String tempStr = null; //临时字符串
		String fileNameStr = null; //上传前文件名
		FileOutputStream fos = null; //文件输出
		File writeFile = null; //保存文件类
		String afterSaveFileName = null; //上传后的文件名
		boolean ifCloseFile = true; //是否文件处于关闭状态
		ByteArrayOutputStream bos = new ByteArrayOutputStream(); //文件输出流
		ByteArrayOutputStream subBos = null; //累加缓存输出流
		byte[] subBytes = null; //累加缓存字节数组
		//ByteArrayOutputStream testBos = new ByteArrayOutputStream(); //测试输出流
		
		try {
			
			while(allSize>correntSize) {
				
				//读取行
				readSize = iGetInputStream().readLine(bufferBytes,0,bufferSize);
				if (readSize<1) {
					break;
				}
				//testBos.write(bufferBytes,0,readSize);
				bos.write(bufferBytes,0,readSize); //放入缓存
				correntSize += readSize;
				if (readSize==bufferSize && !readFileValue) {
					continue;
				}else {
					if(request.getCharacterEncoding()==null) {
						lineStr = new String(bos.toByteArray(),0,bos.size());
					}else {
						lineStr = new String(bos.toByteArray(),0,bos.size(),request.getCharacterEncoding());
					}
					bos = new ByteArrayOutputStream();
				}
				
				if (isFirst) {
					isFirst = false;
					if(request.getCharacterEncoding()==null) {
						pointStr = new String(bufferBytes,0,readSize);
					}else {
						pointStr = new String(bufferBytes,0,readSize,request.getCharacterEncoding());
					}
					if (pointStr.length()>2) {
						pointStr = pointStr.substring(0,pointStr.length()-2);
					}
					readParaName = true;
					readFileValue = false;
					readParaValue = false;
					continue;
				}

				if (readParaName) {
				    if("\r\n".equals(lineStr)) {
				        continue;
				    }
					readParaName = false;
					//获取参数名
					tempStr = lineStr.substring(lineStr.indexOf(tagParaName)+tagParaName.length());
					paraNameStr = BaseUtil.trim(tempStr,"\"","\'","\r","\n");
					if (lineStr.indexOf(tagParaFileName)>-1) {
					      //分割之前的 name=para1;file=  截取到的值 para1;file=
		                   int point = paraNameStr.indexOf(";");
		                    if(point>-1) {
		                        paraNameStr = BaseUtil.trim(paraNameStr.substring(0,point)," ","\t","\"","\'");
		                    }
						//读取文件名
						//强制转换为UTF-8格式，因为如果文件夹为中文名，则无法判断文件夹分隔符
						//后来又发现不用转格式，不会出现乱码，需要进一步分析
						//lineStr = new String(lineStr.getBytes(),"UTF-8"); 
						tempStr = lineStr.substring(lineStr.indexOf(tagParaFileName)+tagParaFileName.length());
						fileNameStr = SFilesUtil.getFileName(BaseUtil.trim(tempStr,"\"","\'","\r","\n"));
						//读无用行Content-Type:
						readSize = iGetInputStream().readLine(bufferBytes,0,bufferSize);
						//if(readSize>0) {testBos.write(bufferBytes,0,readSize);}
						if (fileNameStr!=null) {
							readFileValue = true;
							lastReadSize1 = 0;
							lastReadSize2 = 0;
						}
					}else {
						readParaValue = true;
					}
					//处理报文
					/*
					 * --x-YWKVljoiWFieFXGzqu5FcUVgR00ypD5OW3
					 * Content-Disposition: form-data; name="mobile"
					 * Content-Type: text/plain; charset=UTF-8
					 * Content-Transfer-Encoding: 8bit
					 */
					readSize = iGetInputStream().readLine(bufferBytes,0,bufferSize);
					while(readSize>0) {
					    if(readSize==2 && bufferBytes[0]==13 && bufferBytes[1]==10) {
					        break;
					    }
					    readSize = iGetInputStream().readLine(bufferBytes,0,bufferSize);
					}
					continue;
				}
				if (lineStr.indexOf(pointStr)>-1) {
					readParaName = true; //标识下一行为参数声明行
					if (readParaValue) {
						readParaValue = false;
						if(paraValue.length()>2) {
							putParameter(paraNameStr,paraValue.substring(0,paraValue.length()-2));
						}
						paraValue = new StringBuffer();
						continue;
					}
					if (readFileValue) {
						readFileValue = false;
						ifCloseFile = true;
						
						/*
						 * 将两个缓存中的内容按照多种情况进行保存
						 */
						if(lastReadSize1>0 || lastReadSize2>0) {
						    subBos = new ByteArrayOutputStream();
							if(bufferType==2) {
								//缓存1最后一次接收
							    if(lastReadSize2>0) {
							        subBos.write(lastReadBytes2,0,lastReadSize2);
							    }
							    if(lastReadSize1>0) {
							        subBos.write(lastReadBytes1,0,lastReadSize1);
							    }
							}else {
								//缓存2最后一次接收
                                if(lastReadSize1>0) {
                                    subBos.write(lastReadBytes1,0,lastReadSize1);
                                }
                                if(lastReadSize2>0) {
                                    subBos.write(lastReadBytes2,0,lastReadSize2);
                                }
							}
                            subBytes = subBos.toByteArray();
                            //判断缓存末尾是否为结束符 \0D  \0A
                            if(subBytes.length>1 && subBytes[subBytes.length-2]=='\r' && subBytes[subBytes.length-1]=='\n') {
                                if(subBytes.length>2) {
                                    //可能只有/0D /0A
                                    if(fos!=null) {
                                        fos.write(subBytes,0,subBytes.length-2);
                                    }
                                }
                            }else if(fos!=null) {
                                fos.write(subBytes);
                            }
						}else if(fos!=null) {
							fos.write(bufferBytes,0,readSize);
						}
						try {
							fos.close();
						}catch(Exception e2) {}
						if(fileNameStr.length()>0) {
							//fileNameStr为空是因为页面中存在file对象，但没有上传文件
						    List<String> valueList = getFileNameMap().get(paraNameStr);
						    if(valueList==null) {
						        valueList = new ArrayList<String>();
						        getFileNameMap().put(paraNameStr,valueList);
						    }
						    valueList.add(fileNameStr);
						    
						    valueList = getFileRealNameMap().get(paraNameStr);
						    if(valueList==null) {
						        valueList = new ArrayList<String>();
						        getFileRealNameMap().put(paraNameStr,valueList);
						    }
						    valueList.add(afterSaveFileName);
						}
						continue;
					}
				}
				if (readParaValue) {
					//这部分代码是错的，因为如果参数值中存在回车换行符号，这段语句就把回车换行符号给去掉了
					//所以在最后保存参数值时再去掉末尾多余的回车换行符号
//					if (lineStr.length()>2) {
//						lineStr = lineStr.substring(0,lineStr.length()-2);
//					}
					paraValue.append(lineStr);
					continue;
				}
				if (readFileValue) {
					
					if (ifCloseFile) {
						if(fileNameStr.length()>0) {
							//fileNameStr为空是因为页面中存在file对象，但没有上传文件
							//建立保存文件
							afterSaveFileName = System.currentTimeMillis()+fileNo+getFileExtName(fileNameStr);
							fileNo++;
							writeFile = 
								SFilesUtil.createFile(
										SFilesUtil.getAllFilePath(
												tempPath+"/"+afterSaveFileName+SAVED_EXT_NAME,basePath));
							fos = new FileOutputStream(writeFile,true);
						}
						ifCloseFile = false;
					}
					
					/*
					 * 采用两次缓存方式
					 * 目的是找到读取到文件末尾字符串数组,并去掉文件结束符 13(0D) 10(0A)
					 */
					if(lastReadSize1>0 && lastReadSize2>0) {
						if(bufferType==1) {
						    if(fos!=null) {
						        fos.write(lastReadBytes1,0,lastReadSize1);
						    }
							//lastReadSize1 = 0; 无须在这里清零，因为在下面进行
							//arraycopy时会重新赋值
						}else if(fos!=null){
							fos.write(lastReadBytes2,0,lastReadSize2);
							//lastReadSize2 = 0;
						}
					}
					if(bufferType==1) {
						System.arraycopy(bufferBytes,0,lastReadBytes1,0,readSize);
						lastReadSize1 = readSize;
						bufferType = 2;
					}else {
						System.arraycopy(bufferBytes,0,lastReadBytes2,0,readSize);
						lastReadSize2 = readSize;
						bufferType = 1;
					}
				}
			}
			if (readParaValue) {
				readParaValue = false;
				if(paraValue.length()>2) {
					putParameter(paraNameStr,paraValue.substring(0,paraValue.length()-2));
				}
				paraValue = new StringBuffer();
			}
			
			if (readFileValue) {
				readFileValue = false;
				try {
					fos.close();
				}catch(Exception e2) {}
				if(fileNameStr.length()>0) {
					//fileNameStr为空是因为页面中存在file对象，但没有上传文件
				    List<String> valueList = getFileNameMap().get(paraNameStr);
				    if(valueList==null) {
				        valueList = new ArrayList<String>();
				        getFileNameMap().put(paraNameStr,valueList);
				    }
				    valueList.add(fileNameStr);
				    
				    valueList = getFileRealNameMap().get(paraNameStr);
				    if(valueList==null) {
				        valueList = new ArrayList<String>();
				        getFileRealNameMap().put(paraNameStr,valueList);
				    }
				    valueList.add(afterSaveFileName);
				}
			}
			//System.out.println(testBos.toString()); //测试用
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 将字节数组转换为16进制信息（用于比较内容） 用于测试
	 * 马宝刚
	 * 2010-5-17 上午11:16:20
	 * @param bytes 字节数组
	 * @param from 起始位置
	 * @param size 输出大小
	 * @return 16进制信息
	 */
	public String getHexInfo(byte[] bytes,int from,int size) {
		if(size<1) {
			size = bytes.length-from;
		}
		//构建返回值
		StringBuffer reSbf = new StringBuffer();
		for(int i=from;i<size;i++) {
			//16进制数
			String hex = Integer.toHexString(bytes[i]);
			if(hex.length()>2) {
				hex = hex.substring(hex.length()-2);
			}else if(hex.length()<2) {
				hex = "0"+hex;
			}
			reSbf.append(hex.toUpperCase()).append(" ");
		}
		return reSbf.toString();
	}
	
	/**
	 * 通过文件全名获取文件扩展名
	 * @author 刘虻
	 * 2007-3-12下午12:34:56
	 * @param fileName 文件全名
	 * @return 文件扩展名
	 */
	protected String getFileExtName(String fileName) {
		if (fileName == null) {
			return null;
		}
		if (fileName.lastIndexOf(".")>-1) {
			return fileName.substring(fileName.lastIndexOf("."));
		}
		return "";
	}
	
	
	/**
	 * 设置参数值
	 * @author 刘虻
	 * 2007-3-12下午10:27:49
	 * @param key 参数主键
	 * @param value 参数值
	 */
	protected void putParameter(String key,String value) {
		if (key==null || value==null) {
			return;
		}
		//上传文件的同时传参时，也做一下URL转码
		try {
			key = URLDecoder.decode(key, "UTF-8");
		}catch(Exception e) {
			e.printStackTrace();
		}
		try {
			value = URLDecoder.decode(value, "UTF-8");
		}catch(Exception e) {
			e.printStackTrace();
		}
		//获取
		String[] values =
                getParameterMap().get(key);
		if (values==null) {
			values = new String[1];
			values[0] = value;
			getParameterMap().put(key,values);
		}else {
			//新的数组
			String[] newValues = new String[values.length+1];
			System.arraycopy(values, 0, newValues, 0, values.length);
			newValues[newValues.length-1] = value;
			getParameterMap().put(key,newValues);
		}
	}



	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:45:27
	 */
	public String getAuthType() {
		return request.getAuthType();
	}



	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:46:07
	 */
	public String getContextPath() {
		return request.getContextPath();
	}



	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:51:20
	 */
	public ICookie[] iGetCookies() {
		return request.iGetCookies();
	}



	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:51:33
	 */
	public long getDateHeader(String arg0) {
		return request.getDateHeader(arg0);
	}



	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:51:49
	 */
	public String getHeader(String arg0) {
		return request.getHeader(arg0);
	}



	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:52:03
	 */
	public Enumeration<String> getHeaderNames() {
		return request.getHeaderNames();
	}



	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:52:16
	 */
	public Enumeration<String> getHeaders(String arg0) {
		return request.getHeaders(arg0);
	}



	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:52:32
	 */
	public int getIntHeader(String arg0) {
		return request.getIntHeader(arg0);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:52:47
	 */
	public String getMethod() {
		return request.getMethod();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:52:59
	 */
	public String getPathInfo() {
		return request.getPathInfo();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:53:12
	 */
	public String getPathTranslated() {
		return request.getPathTranslated();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:53:29
	 */
	public String getQueryString() {
		return request.getQueryString();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:53:41
	 */
	public String getRemoteUser() {	
		return request.getRemoteUser();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:54:00
	 */
	public String getRequestURI() {
		return request.getRequestURI();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:54:12
	 */
	public StringBuffer getRequestURL() {
		return request.getRequestURL();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:54:26
	 */
	public String getRequestedSessionId() {
		return request.getRequestedSessionId();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:54:41
	 */
	public String getServletPath() {
		return request.getServletPath();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:54:54
	 */
	public IHttpSession iGetSession() {
		return request.iGetSession();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:55:06
	 */
	public IHttpSession iGetSession(boolean arg0) {
		return request.iGetSession(arg0);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:55:20
	 */
	public Principal getUserPrincipal() {
		return request.getUserPrincipal();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:55:36
	 */
	public boolean isRequestedSessionIdFromCookie() {
		return request.isRequestedSessionIdFromCookie();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:55:51
	 */
	public boolean isRequestedSessionIdFromURL() {
		return request.isRequestedSessionIdFromURL();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:56:23
	 */
	public boolean isRequestedSessionIdValid() {
		return request.isRequestedSessionIdValid();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:56:45
	 */
	public boolean isUserInRole(String arg0) {
		return request.isUserInRole(arg0);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:56:58
	 */
	public Object getAttribute(String arg0) {
		return request.getAttribute(arg0);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:57:18
	 */
	public Enumeration<String> getAttributeNames() {
		return request.getAttributeNames();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:57:29
	 */
	public String getCharacterEncoding() {
		return request.getCharacterEncoding();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:57:47
	 */
	public int getContentLength() {
		return request.getContentLength();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:58:07
	 */
	public String getContentType() {
		return request.getContentType();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:58:20
	 */
	public ServletInputStream iGetInputStream() throws IOException {
		if (webInputStream==null) {
			webInputStream = request.iGetInputStream();
		}
		return webInputStream;
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:58:33
	 */
	public Locale getLocale() {
		return request.getLocale();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:58:47
	 */
	public Enumeration<Locale> getLocales() {
		return request.getLocales();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午09:58:58
	 */
	public String getParameter(String arg0) {
		String[] values = getParameterMap().get(arg0);
		if (values==null || values.length<1) {
			return null;
		}
		return values[0];
	}

	
	   /**
     * 设置参数值
     * @param key          参数主键
     * @param values      参数值
     * 2014年6月12日
     * @author 马宝刚
     */
    public void setParameter(String key,String[] values) {
        getParameterMap().put(key,values);
    }

	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:01:07
	 */
	public Enumeration<String> getParameterNames() {
		return new EnumerationImpl(BaseUtil.getMapKeys(getParameterMap()));
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:06:14
	 */
	public String[] getParameterValues(String arg0) {
		return getParameterMap().get(arg0);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:08:08
	 */
	public String getProtocol() {
		return request.getProtocol();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:08:27
	 */
	public BufferedReader getReader() throws IOException {
		return request.getReader();
	}


	/**
	 * @deprecated
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:08:40
	 */
    public String getRealPath(String arg0) {
		return request.getRealPath(arg0);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:08:58
	 */
	public String getRemoteAddr() {
		return request.getRemoteAddr();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:09:12
	 */
	public String getRemoteHost() {
		return request.getRemoteHost();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:09:23
	 */
	public IRequestDispatcher iGetRequestDispatcher(String arg0) {
		return request.iGetRequestDispatcher(arg0);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:09:35
	 */
	public String getScheme() {
		return request.getScheme();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:09:46
	 */
	public String getServerName() {
		return request.getServerName();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:10:01
	 */
	public int getServerPort() {
		return request.getServerPort();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:10:10
	 */
	public boolean isSecure() {
		return request.isSecure();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:10:24
	 */
	public void removeAttribute(String arg0) {
		request.removeAttribute(arg0);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:10:37
	 */
	public void setAttribute(String arg0, Object arg1) {
		request.setAttribute(arg0,arg1);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13上午10:10:56
	 */
	public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException {
		request.setCharacterEncoding(arg0);
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13下午08:38:36
	 */
	public String getLocalAddr() {
		return request.getLocalAddr();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13下午08:38:51
	 */
	public String getLocalName() {
		return request.getLocalName();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13下午08:39:08
	 */
	public int getLocalPort() {
		return request.getLocalPort();
	}


	/**
	 * 覆盖方法
	 * @author 刘虻
	 * 2007-3-13下午08:39:21
	 */
	public int getRemotePort() {
		return request.getRemotePort();
	}
	
	
	/**
	 * 获取上传后的文件路径
	 * 刘虻
	 * 2011-5-5 下午01:53:24
	 * @param fileTagName 上传文件的标签名 <input type="file" name="标签名" />
	 * @return 上传后的文件路径
	 */
	public String[] getFilePath(String fileTagName) {
		//文件名
		List<String> fileNameList = getFileRealNameMap().get(fileTagName);
		if(fileNameList==null || fileNameList.size()<1) {
			return new String[0];
		}
		//构造返回值
		String[] reStrs = new String[fileNameList.size()];
		for(int i=0;i<fileNameList.size();i++) {
		    reStrs[i] = SFilesUtil.getAllFilePath(tempPath+"/"+fileNameList.get(i),basePath);
		}
		return reStrs;
	}
	
	/**
	 * 通过上传文件标签名获取上传的文件对象数组
	 * @param fileTagName 上传文件标签名
	 * @return 对应的上传文件对象数组
	 * 2014年6月18日
	 * @author 马宝刚
	 */
	public UploadFile[] getUploadFiles(String fileTagName) {
        //文件真实路径序列
        List<String> rNameList = getFileRealNameMap().get(fileTagName);
        //文件名序列
        List<String> fNameList = getFileNameMap().get(fileTagName);
        
        if(rNameList==null || rNameList.size()<1 || rNameList.size()!=fNameList.size()) {
            return new UploadFile[0];
        }
        //构造返回值
        UploadFile[] ufs = new UploadFile[rNameList.size()];
        for(int i=0;i<rNameList.size();i++) {
            ufs[i] = new UploadFile();
            ufs[i].tempPath = getTempPath();
            ufs[i].uploadBasePath = getBasePath();
            ufs[i].name = fileTagName;
            ufs[i].srcFileName = fNameList.get(i);
            ufs[i].objFileName = rNameList.get(i);
            ufs[i].filePath = SFilesUtil.getAllFilePath(tempPath+"/"+rNameList.get(i),basePath);
        }
        return ufs;
    }
	
	/**
	 * 上传文件数量
	 * @return 上传文件数量
	 * 2015年3月25日
	 * @author 马宝刚
	 */
	public int getUploadCount() {
	    return getFileNameMap().size();
	}
	
	
	/**
	 * 通过上传文件标签名获取首个同名上传的文件对象
	 * @param fileTagName 上传文件标签名
	 * @return 文件对象
	 * 2015年3月25日
	 * @author 马宝刚
	 */
	public UploadFile getUploadFile(String fileTagName) {
        //文件真实路径序列
        List<String> rNameList = getFileRealNameMap().get(fileTagName);
        //文件名序列
        List<String> fNameList = getFileNameMap().get(fileTagName);
        
        if(rNameList==null || rNameList.size()<1 || rNameList.size()!=fNameList.size()) {
            return null;
        }
        //构建返回值
        UploadFile res = new UploadFile();
        res.tempPath = getTempPath();
        res.uploadBasePath = getBasePath();
        res.name = fileTagName;
        res.srcFileName = fNameList.get(0);
        res.objFileName = rNameList.get(0);
        res.filePath = SFilesUtil.getAllFilePath(tempPath+"/"+rNameList.get(0),basePath);
        return res;
    }
	
	/**
	 * 获取上传文件根路径
	 * 刘虻
	 * 2011-5-5 下午04:59:05
	 * @return 上传文件根路径
	 */
	public String getBasePath() {
		return basePath;
	}
	
	/**
	 * 获取临时上传文件路径（相对路径）
	 * 刘虻
	 * 2011-5-5 下午04:58:09
	 * @return 临时上传文件路径
	 */
	public String getTempPath() {
		return tempPath;
	}
}
